package aor2.common;

import aor2.components.Signal;
import aor2.cpu.ClockCPU;
import javax.swing.JOptionPane;

/**
 * 
 * Limited size stack. Tracks up to <b>capacity</b> records.
 * 
 * @author momcilo
 * 
 */
@SuppressWarnings("rawtypes")
public class Tracker {

	private int capacity;
	private TrackerRecord[] history;
	private int bottom, top;

	public Tracker(int capacity) {
		super();
		this.capacity = Math.max(capacity + 1, 6);
		history = new TrackerRecord[this.capacity];
		for (int i = 0; i < this.capacity; i++) {
			history[i] = null;
		}
		bottom = top = 0;
	}

	public Tracker() {
		this(30);
	}

	@SuppressWarnings("unchecked")
	public void put(TrackerRecord tr) {
		TrackerRecord topElement = getFromTop(0);
		if (topElement != null
				&& topElement.getMark().compareTo(tr.getMark()) == 0)
			history[(top - 1/* 0th */+ capacity) % capacity] = tr;
		else {
			history[top] = tr;
			top = (top + 1) % capacity;
		}

		if (top == bottom) {
			bottom = (bottom + 1) % capacity;
		}
	}

	public TrackerRecord takeFromTop() {
		TrackerRecord tr = getFromTop(0);
		if (tr != null) {
			int hlp = top;
			top = (top - 1 + capacity) % capacity;
			// if (top == bottom)
			// TODO
                        if (top < 0)
                            JOptionPane.showMessageDialog(null,
					hlp);
		}
		return tr;
	}

	/**
	 * 
	 * @param i
	 *            - level from the top of the stack. index of i-th previous
	 *            record.
	 * @return
	 */
	public TrackerRecord getFromTop(int i) {
		if (i < 0 || i >= capacity)
			return null;
		return history[(top - 1/* 0th */+ capacity - i) % capacity];
	}

	public TrackerRecord getFromBottom(int i) {
		if (i < 0 || i >= capacity - 1)
			return null;
		return history[(bottom + i) % capacity];
	}

	@Override
	public String toString() {
		StringBuffer buffer = new StringBuffer();
		buffer.append('[');
		for (int i = 0; i < capacity - 1 && null != getFromBottom(i); i++) {
			buffer.append(getFromBottom(i).toString()).append(", ");
		}
		int index = buffer.lastIndexOf(", ");
		if (index >= 0)
			buffer.delete(index, index + 2);
		buffer.append(']');
		return "Tracker [capacity=" + capacity + ", history="
				+ buffer.toString() + ", bottom=" + bottom + ", top=" + top
				+ "]";
	}

	public void info(Signal s) {
		System.out.println("\n=======================");
		System.out.println(s.toString());
		System.out.println("=======================\n");
	}

	public static void main(String[] args) {
		Tracker t = new Tracker();
		ClockCPU cpu = ClockCPU.getInstance();
		Signal s = new Signal(true);

		System.out.println("s<=true");
		t.info(s);

		// cpu.nextClkPart();
		// s.setActive(false);
		// System.out.println("s<=false");
		// t.info(s);
		//
		//
		// System.out.println("s<=true");
		// cpu.nextClkPart();
		// s.setActive(true);
		// t.info(s);
		//
		//
		// System.out.println("s<=false");
		// cpu.nextClkPart();
		// s.setActive(false);
		// t.info(s);
		//
		//
		// System.out.println("s<=true");
		// cpu.nextClkPart();
		// s.setActive(true);
		// t.info(s);
		//
		//
		// System.out.println("s<=false");
		// cpu.nextClkPart();
		// s.setActive(false);
		// t.info(s);
		//
		//
		// System.out.println("s<=true");
		// cpu.nextClkPart();
		// s.setActive(true);
		// t.info(s);
		//
		// System.out.println("s<=true");
		// cpu.nextClkPart();
		// s.setActive(true);
		// t.info(s);
		//
		// System.out.println("s<=true");
		// cpu.nextClkPart();
		// s.setActive(true);
		// t.info(s);
		//
		// System.out.println("s<=true");
		// cpu.nextClkPart();
		// s.setActive(true);
		// t.info(s);
		//
		// System.out.println("s<=true");
		// cpu.nextClkPart();
		// s.setActive(true);
		// t.info(s);
		//
		// System.out.println("s<=true");
		// cpu.nextClkPart();
		// s.setActive(true);
		// t.info(s);
		//
		// System.out.println("s<=true");
		// cpu.nextClkPart();
		// s.setActive(true);
		// t.info(s);

		System.out.println("s<=true");
		cpu.nextClkPart();
		s.setActive(true);
		t.info(s);
		System.out.println("\n\n\n\n\n\n*******************\n");

		System.out.println("s<=false");
		cpu.nextClkPart();
		s.setActive(false);
		t.info(s);

		System.out.println("s<=false");
		s.setActive(false);
		t.info(s);

		System.out.println("s<=false");
		s.setActive(false);
		t.info(s);

		System.out.println("s<=true");
		s.setActive(true);
		t.info(s);

		System.out.println("s<=true");
		s.setActive(true);
		t.info(s);

		System.out.println("s<=true");
		s.setActive(true);
		t.info(s);

		System.out.println("s<=true");
		s.setActive(true);
		t.info(s);

		System.out.println("s<=false");
		s.setActive(false);
		t.info(s);

		System.out.println("s<=true");
		s.setActive(true);
		t.info(s);

		System.out.println("s<=false");
		cpu.nextClkPart();
		s.setActive(false);
		t.info(s);

		System.out.println("s<=true");
		s.setActive(true);
		t.info(s);
	}

}
